package no.uio.ifi.cop.prover.rete;

/// import java.util.HashMap;
import java.util.ArrayList;
import java.util.LinkedList;


import no.uio.ifi.cop.common.Log;
/// import no.uio.ifi.cop.cl.Axiom;
import no.uio.ifi.cop.cl.Term;
/// import no.uio.ifi.cop.cl.Conjunction;
import no.uio.ifi.cop.cl.Predicate;
import no.uio.ifi.cop.cl.Substitution;

/**
 * Represents an Alpha node in a RETE matching scheme.
 *
 * NOTE: In actual RETE algorithm all Alpha nodes which
 * have a unifying substitution, and therefore match the
 * same terms are joined into one Alpha node. In this
 * implementation this is not done, we only check for
 * similarity through: p1.toString().equals(p2.toString()) 
 * i.e., if they are syntactically identical, this may
 * force us to do a few extra matches, but this is by far
 * the heavy part of the algorithm.
 *
 * @version 1.0
 * @author bjarneh@ifi.uio.no
 */

public final class AlphaNode implements Cloneable{

    Predicate predicate;
    ArrayList<Substitution> matches;
    ArrayList<BetaNode> children;


    public AlphaNode(Predicate pred){
        predicate = pred;
        matches = new ArrayList<Substitution>(70);
        children = new ArrayList<BetaNode>(50);
    }

    // for cloning puposes
    private AlphaNode(Predicate pred, ArrayList<Substitution> clones){
        predicate = pred;
        matches   = clones;
        children  = new ArrayList<BetaNode>();
    }

    public BetaNode getBeta(int id){
        BetaNode bn = new BetaNode(this, id);
        children.add( bn );
        return bn;
    }

    public LinkedList<MatchList> match(Term t){

        MatchList tmp;
        LinkedList<MatchList> list = new LinkedList<MatchList>();

        Substitution subst = new Substitution();

        if( predicate.match( subst, t ) ){

            // add substitution to my list of matches
            matches.add( subst );

            for(BetaNode child: children){
                tmp = child.match();
                if( tmp != null ){
                    list.add( tmp );
                }
            }
        }

        return list;
    }

    public Substitution get(int i){
        if( i >= matches.size() ){
            Log.fatal("trying to access Substitution > size() ");
        }
        return matches.get(i);
    }

    public boolean equals(Object other){
        if( other instanceof AlphaNode ){
            AlphaNode a_other = (AlphaNode) other;
            return a_other.predicate.equals(predicate);
        }
        return false;
    }

    public void infoString(StringBuilder sb){
        sb.append(String.format(" %s -> ", predicate));
        for( Substitution subst: matches ){
            sb.append(String.format(" %s ", subst));
        }
        sb.append("\n");
    }

    public void addBeta(BetaNode beta){
        children.add( beta );
    }

    public AlphaNode clone(){
        ArrayList<Substitution> matchClones = new ArrayList<Substitution>();
        for( Substitution subst : matches ){
            matchClones.add( subst.clone() );
        }
        return new AlphaNode( predicate, matchClones );
    }

    public String toString(){
        return String.format("@AlphaNode(%s)",predicate);
    }
}
